home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / Genie / Projects / AEGizmos 1.4.2 / Source / Sources / AEPrint.c < prev   
Encoding:
C/C++ Source or Header  |  2000-06-24  |  11.0 KB  |  477 lines

  1. /*
  2.  *    AppleEvent Printer Function
  3.  *    by Jens Peter Alfke
  4.  *
  5.  *    Copyright ©1991-1993 Apple Computer, Inc. All rights reserved.
  6.  *
  7.  *    APPLE CONFIDENTIAL
  8.  */
  9.  
  10.  
  11. /*
  12.     CHANGE HISTORY:
  13.      ...zillions of changes from 2/91 until...
  14.      7/08/93    jpa        Allow for bufStr to be NULL, and return length, to support preflighting.
  15.                          Don't truncate hex dumps.
  16.      7/09/93    jpa        No, break length-counting into separate function (AEPrintLength).
  17.      9/29/93    jpa        Remove calls to vsprintf (cripping floating-point display, oh well...)
  18.     10/11/93    jpa        Display floats by coercing from 'sing' -> 'TEXT'.
  19.      4/14/94    jpa        Fix warnings for Metrowerks.
  20.      9/08/94    jpa        Added bufputOSType to fix quoting problems when re-parsing output.
  21.     10/03/94    jpa        Fixed heinous bug in printDescList that was always changing type to
  22.                         'aevt' on the way out.
  23.      3/20/95    jpa        **AEGizmos 1.4
  24. */
  25.  
  26.  
  27. #include <ctype.h>
  28. #include <stdarg.h>
  29. #include <Errors.h>
  30. #include <Packages.h>
  31. #include <AppleEvents.h>
  32. #include <NumberFormatting.h>  // 1998-01-02 JDJ
  33. #include "AEPrint.h"
  34.  
  35.  
  36. typedef struct {
  37.     char *str;
  38.     long len;
  39. } Buf;
  40.  
  41.  
  42. static OSErr printDesc( Buf *buf, register AEDesc *desc );
  43.  
  44.  
  45. #ifdef THINK_C
  46. #if !__option(macsbug_names)
  47.     // Always turn on macsbug names for the non-static functions.
  48.     #define NO_NAMES
  49.     #pragma options(macsbug_names)
  50. #endif
  51. #endif
  52.  
  53.  
  54. /* AE_PRINT  The big kahuna. Print any AEDesc into bufStr, up to bufLen chars */
  55. OSErr
  56. AEPrint( AEDesc *desc, char *bufStr, long bufSize )
  57. {
  58.     Buf buf;
  59.     
  60.     if( !desc || !bufStr )
  61.         return paramErr;
  62.     buf.str = bufStr;
  63.     buf.len = bufSize -1;
  64.     bufStr[0] = '\0';
  65.     
  66.     return printDesc(&buf,desc);
  67. }
  68.  
  69.  
  70. /* AE_PRINT_SIZE  Compute the size of string (incl. null byte) AEPrint will build. */
  71. OSErr
  72. AEPrintSize( AEDesc *desc, long *stringLength )
  73. {
  74.     Buf buf;
  75.     OSErr err;
  76.     
  77.     if( !desc || !stringLength )
  78.         return paramErr;
  79.     buf.str = NULL;
  80.     buf.len = 0x7FFFFFF0;
  81.     
  82.     err= printDesc(&buf,desc);
  83.     
  84.     *stringLength = 0x7FFFFFF0 +1 - buf.len;        // Set to size of returned string (length+1)
  85.     return err;
  86. }
  87.  
  88.  
  89. #ifdef NO_NAMES
  90.     #undef NO_NAMES
  91.     #pragma options(!macsbug_names)
  92. #endif
  93.  
  94.  
  95. /*******************************  THE UTILITY BELT  ************************************/
  96.  
  97.  
  98. /* BUF_PUT  Copy data to the buffer */
  99. static void
  100. bufput( register Buf *buf, void *data, register long len )
  101. {
  102.     if( buf->len > 0 ) {
  103.         if( buf->len < len )
  104.             len = buf->len;
  105.         if( buf->str ) {                        // Only write data if we have a place for it
  106.             BlockMove(data,buf->str,len);
  107.             buf->str += len;
  108.             buf->str[0] = '\0';
  109.         }
  110.         buf->len -= len;
  111.     }
  112. }
  113.  
  114.  
  115. /* BUF_PUT_C  Copy a single char to the buffer */
  116. static void
  117. bufputc( register Buf *buf, char c )
  118. {
  119.     if( buf->len > 0 ) {
  120.         buf->len--;
  121.         if( buf->str ) {
  122.             *(buf->str)++ = c;
  123.             buf->str[0] = '\0';
  124.         }
  125.     }
  126. }
  127.  
  128.  
  129. /* BUF_PUT_S  Write a C string to the buffer */
  130. static void
  131. bufputs( Buf *buf, register char *str )
  132. {
  133.     register long len = buf->len;
  134.     register char *dst= buf->str;
  135.     
  136.     if( buf->str ) {
  137.         for(; *str && len>0; len-- )
  138.             *dst++ = *str++;
  139.         *dst = '\0';
  140.         buf->str = dst;
  141.     } else
  142.         for(; *str && len>0; len-- )            // No buffer, just count length of str
  143.             str++;
  144.     buf->len = len;
  145. }
  146.  
  147.  
  148. /* BUF_PUT_OSTYPE  Write a 4-character code to the buffer */
  149. static void
  150. bufputOSType( Buf *buf, OSType type )
  151. {
  152.     // If type contains any nonalphabetic chars, quote it.
  153.     // $$$$$ This still won't handle embedded single quotes.
  154.     short i;
  155.     unsigned char c;
  156.     Boolean space=false, alpha=false;
  157.     
  158.     for( i=0; i<4; i++ )
  159.         if( isalpha( c=((unsigned char*)&type)[i] ) ) {
  160.             if( space )
  161.                 break;                        // alpha after a space is bad
  162.             alpha = true;
  163.         } else if( c==' ' && alpha )
  164.             space = true;                    // space is ok after alpha chars
  165.         else
  166.             break;
  167.  
  168.     if( i<4 )
  169.         bufputc(buf,'\'');
  170.     bufput(buf,&type,sizeof(type));
  171.     if( i<4 )
  172.         bufputc(buf,'\'');
  173. }
  174.  
  175.  
  176. /* BUF_PUT_FLOAT  Write a floating-point number to a buffer */
  177. static OSErr
  178. bufputfloat( Buf *buf, float f )
  179. {
  180.     AEDesc desc, textDesc;
  181.     OSErr err;
  182.     
  183.     err= AECreateDesc(typeSMFloat,&f,sizeof(f), &desc);
  184.     if( err ) return err;
  185.     err= AECoerceDesc(&desc,'TEXT',&textDesc);
  186.     AEDisposeDesc(&desc);
  187.     if( !err ) {
  188.         bufput(buf,*textDesc.dataHandle,GetHandleSize(textDesc.dataHandle));
  189.         AEDisposeDesc(&textDesc);
  190.     }
  191.     return err;
  192. }
  193.  
  194.  
  195. /***************************  SUPPORT FOR PRINTING EVENTS  ********************************/
  196.  
  197.  
  198. static OSErr
  199. getOptionalParams( AppleEvent *event, AEKeyword** *keys )
  200. {
  201.     OSErr err;
  202.     AEDescList optionals;
  203.     long n, realSize;
  204.     AEKeyword key, optionalKey;
  205.     DescType type;
  206.     
  207.     *keys = NULL;
  208.     err= AEGetAttributeDesc( event, keyOptionalKeywordAttr,typeAEList, &optionals );
  209.     if( err )
  210.         if( err==errAEDescNotFound )
  211.             return noErr;
  212.         else
  213.             return err;
  214.     
  215.     err= AECountItems(&optionals, &n);
  216.     if( err ) goto exit;
  217.     if( n<=0 )
  218.         goto exit;
  219.     //*keys = (void*) NewHandle(n*sizeof(AEKeyword));
  220.     *keys = (AEKeyword**) NewHandle(n*sizeof(AEKeyword));
  221.     if( (err= MemError()) != noErr ) goto exit;
  222.     
  223.     for( ; n>0; n-- ) {
  224.         err= AEGetNthPtr(&optionals,n,typeKeyword, &key,&type,
  225.                          (Ptr)&optionalKey,sizeof(optionalKey),&realSize);
  226.         if( err ) goto exit;
  227.         (**keys)[n-1] = optionalKey;
  228.     }
  229.  
  230. exit:
  231.     AEDisposeDesc(&optionals);
  232.     if( err && *keys ) {
  233.         DisposeHandle((Handle)*keys);
  234.         *keys = NULL;
  235.     }
  236.     return err;
  237. }
  238.  
  239.  
  240. static Boolean
  241. keyInList( AEKeyword key, AEKeyword **list )
  242. {
  243.     AEKeyword *elem;
  244.     long i;
  245.     
  246.     if( list==NULL )
  247.         return false;
  248.     for( elem= *list, i= GetHandleSize((Handle)list);  i>=0;  i-=sizeof(AEKeyword), elem++ )
  249.         if( key == *elem )
  250.             return true;
  251.     return false;
  252. }
  253.  
  254.  
  255. /*******************************  THE MAIN ROUTINES  ***********************************/
  256.  
  257.  
  258. /* PRINT_DESC_LIST  Print a descriptor list -- AEDescList, AERecord or AppleEvent */
  259. static OSErr
  260. printDescList( Buf *buf, AEDescList *desc, DescType originalType )
  261. {
  262.     DescType type = desc->descriptorType;
  263.     long i, size;
  264.     long itemNo = 0;
  265.     AEKeyword keyword;
  266.     AEDesc tempDesc;
  267.     short meta=false, doMeta=false;
  268.     AEKeyword **optionals = NULL;
  269.     OSErr err;
  270.     
  271.     if( type=='aevt' ) {
  272.         AEEventClass eventClass;
  273.         AEEventID eventID;
  274.         DescType realType;
  275.         long realSize;
  276.         
  277.         err= AEGetAttributePtr(    desc, keyEventClassAttr,typeType, &realType,
  278.                                 (Ptr)&eventClass, sizeof(eventClass), &realSize );
  279.         if( err ) goto exit;
  280.         bufputOSType(buf,eventClass);
  281.         
  282.         err= AEGetAttributePtr(    desc, keyEventIDAttr,typeType, &realType,
  283.                                 (Ptr)&eventID, sizeof(eventID), &realSize );
  284.         if( err ) goto exit;
  285.         bufputc(buf, '\\');
  286.         bufputOSType(buf,eventID);
  287.         
  288.         err= getOptionalParams(desc, &optionals);
  289.         if( err ) goto exit;
  290.         
  291.         doMeta = true;
  292.         
  293.         bufputc(buf, '{');
  294.         
  295.     } else if( type=='list' )
  296.         bufputc(buf, '[');                                /* Open-bracket for list */
  297.         
  298.     else {
  299.         if( originalType != 'reco' )
  300.             bufputOSType(buf, originalType);            /* Show type for coerced record */
  301.         bufputc(buf, '{');                                /* Open-brace for record */
  302.     }
  303.     
  304.     // Now get all the items and print them.
  305.     // If this is an Apple event, we will go around twice: one to print the parameters,
  306.     // and again to print the attributes.
  307.  
  308.     for( meta=false; meta<=doMeta; meta++) {
  309.         if( meta ) {
  310.             desc->descriptorType = 'meta';
  311.             if( optionals )
  312.                 DisposeHandle((Handle)optionals);
  313.             optionals = NULL;
  314.         }
  315.  
  316.         err= AECountItems(desc, &size);
  317.         if( err ) goto exit;
  318.         
  319.         for( i=1; i<=size; i++ ) {                            /* Loop through items: */
  320.             err= AEGetNthDesc(desc,i, typeWildCard, &keyword,&tempDesc);
  321.             if( err )
  322.                 goto exit;
  323.                 
  324.             if( meta && keyword=='optk' )                        // Skip optional-params attribute
  325.                 continue;
  326.                 
  327.             if( itemNo++ >0 )
  328.                 bufputs(buf, ", ");
  329.             if( meta )
  330.                 bufputc(buf,'&');                                // Prefix for metaparam (attribute)
  331.             else if( keyInList(keyword,optionals) )                // Prefix for optional parameter
  332.                 bufputc(buf,'~');
  333.             if( type!='list' ) {
  334.                 bufputOSType(buf,keyword);                        /* If we're in a record, show key */
  335.                 bufputc(buf,':');
  336.             }
  337.             err= printDesc(buf,&tempDesc);                        /* Recursively print item */
  338.             AEDisposeDesc(&tempDesc);
  339.             if( err ) goto exit;
  340.         }
  341.     }
  342.     
  343.     if( type=='list' )                    /* Close list or record */
  344.         bufputc(buf, ']');
  345.     else
  346.         bufputc(buf, '}');
  347.  
  348. exit:
  349.     if( optionals )
  350.         DisposeHandle((Handle)optionals);
  351.     if( doMeta )
  352.         desc->descriptorType = 'aevt';        // Fix it if we'd changed it to 'meta'
  353.     return err;
  354. }
  355.  
  356.  
  357. /* HEX_DUMP_DESC  Official punting routine. Produce hex dump of descriptor */
  358. static OSErr
  359. hexDumpDesc( Buf *buf, AEDesc *desc )
  360. {
  361.     unsigned char *data;
  362.     long count,n;
  363.     unsigned char byte;
  364.     char hex[] = "0123456789ABCDEF";
  365.     
  366.     bufputOSType(buf, desc->descriptorType);
  367.     bufputs(buf, "(«");
  368.     
  369.     //data = (void*)*desc->dataHandle;
  370.     data = (unsigned char *)*desc->dataHandle;
  371.     count = GetHandleSize(desc->dataHandle);
  372.  
  373.     n = count;
  374. #ifdef _MAX_HEX_DUMP_LENGTH_
  375.     if( n>_MAX_HEX_DUMP_LENGTH_ )
  376.         n = _MAX_HEX_DUMP_LENGTH_;
  377. #endif
  378.     if( n*2>buf->len )
  379.         n = buf->len>>1;                        // No sense going past end of buffer
  380.  
  381.     while( n-- >0 ) {
  382.         byte = *data++;
  383.         bufputc(buf,hex[byte>>4]);
  384.         bufputc(buf,hex[byte&0x0F]);
  385.     }
  386. #ifdef _MAX_HEX_DUMP_LENGTH_
  387.     if( count>_MAX_HEX_DUMP_LENGTH_ )
  388.         bufputc(buf,'…');
  389. #endif
  390.     bufputs(buf,"»)");
  391.     return noErr;
  392. }
  393.  
  394.  
  395. /*******************************  THE BIG KAHUNA  ************************************/
  396.  
  397.  
  398. /* PRINT_DESC  The big kahuna. Print any AEDesc */
  399. static OSErr
  400. printDesc( Buf *buf, register AEDesc *desc )
  401. {
  402.     OSErr err = noErr;
  403.     AEDesc tempDesc;
  404.     
  405.     if( desc->dataHandle==NULL || GetHandleSize(desc->dataHandle)==0 ) {
  406.         bufputc(buf,'\'');
  407.         bufputOSType(buf, desc->descriptorType);    /* No data */
  408.         bufputs(buf,"'()");
  409.         return noErr;
  410.     }
  411.     
  412.     switch( desc->descriptorType ) {
  413.         case 'bool':                                /* Integer types: */
  414.         case 'shor':
  415.         case 'long':
  416.             err= AECoerceDesc(desc,'long',&tempDesc);        /* Coerce to longint */
  417.             if( !err ) {
  418.                 unsigned char str[12];
  419.                 NumToString(**(long**)tempDesc.dataHandle,str);
  420.                 bufput(buf,str+1,str[0]);
  421.             } else if( err==errAECoercionFail )
  422.                 err= hexDumpDesc(buf,desc);
  423.             AEDisposeDesc(&tempDesc);
  424.             break;
  425.  
  426.         case 'sing':                                /* Floating-point types: */
  427.             bufputfloat(buf, **(float**)desc->dataHandle);
  428.             break;
  429.         case 'doub':
  430.             bufputfloat(buf, **(double**)desc->dataHandle);
  431.             break;
  432.         case 'exte':
  433.             bufputfloat(buf, **(long double**)desc->dataHandle);
  434.             break;
  435.  
  436.         case 'enum':                                /* 4-letter code: */
  437.             bufputOSType(buf, **(OSType**)desc->dataHandle);
  438.             break;
  439.  
  440.         case 'type':                                /* 4-letter code as 'type': */
  441.             bufputs(buf,"type(");
  442.             bufputOSType(buf, **(OSType**)desc->dataHandle);
  443.             bufputs(buf,")");
  444.             break;
  445.  
  446.         case 'TEXT':                                /* Text string: */
  447.             bufputc(buf,'“');
  448.             bufput(buf, *desc->dataHandle,GetHandleSize(desc->dataHandle));
  449.             bufputc(buf,'”');
  450.             break;
  451.  
  452.         case 'aevt':                                /* Apple event! */
  453.             err= printDescList(buf,desc,'aevt');
  454.             break;
  455.         
  456.         case 'list':                                /* AEDescList: */
  457.             err= printDescList(buf,desc,'list');
  458.             break;
  459.         
  460.         default:                                    /* AERecord, and everything else: */
  461.             if( desc->descriptorType=='reco' )
  462.                 tempDesc = *desc;
  463.             else
  464.                 err= AECoerceDesc(desc,'reco',&tempDesc);
  465.             
  466.             if( err==noErr ) {
  467.                 err= printDescList(buf,&tempDesc,        /* Made it a record, print it */
  468.                                     desc->descriptorType);
  469.                 if( desc->descriptorType != 'reco' )
  470.                     AEDisposeDesc(&tempDesc);
  471.             } else if( err==errAECoercionFail )            /* Couldn't make it a record */
  472.                 err= hexDumpDesc(buf,desc);
  473.             break;
  474.     }
  475.     return err;
  476. }
  477.